#include <jni.h>
#include <string>
#include <android/log.h>
#include <malloc.h>

extern "C"
{
#include  "librtmp/rtmp.h"
}
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,"well",__VA_ARGS__)

// 用于保存 sps、pps 结构体
typedef struct {
    RTMP *rtmp;
    int8_t *sps;    // sps数组
    int8_t *pps;    // pps数组
    int16_t sps_len;// sps数组长度
    int16_t pps_len;// pps数组长度
} Live;
Live *live = nullptr;

// 一、连接服务器
extern "C" JNIEXPORT jboolean JNICALL Java_com_np_rtmpdump3_ScreenLive_connect(JNIEnv *env, jobject thiz, jstring url_) {

    const char *url = env->GetStringUTFChars(url_, 0);
    int ret;
    do {
        //实例化，但是不会清空数据
        live = (Live *) malloc(sizeof(Live));
        //清空里面的数据
        memset(live, 0, sizeof(Live));

        live->rtmp = RTMP_Alloc();
        RTMP_Init(live->rtmp);
        live->rtmp->Link.timeout = 10;
        if (!(ret = RTMP_SetupURL(live->rtmp, (char *) url))) break;
        RTMP_EnableWrite(live->rtmp);
        if (!(ret = RTMP_Connect(live->rtmp, 0))) break;
        if (!(ret = RTMP_ConnectStream(live->rtmp, 0))) break;
        //到这一步,就链接成功了
    } while (0);
    if (!ret && live) {
        free(live);
        live = nullptr;
    }
    env->ReleaseStringUTFChars(url_, url);
    return ret;
}

// 二、sps和pps解析，缓存sps和pps信息
void prepareVideo(int8_t *data, int len, Live *live) {

    for (int i = 0; i < len; i++) {
        //防止越界
        if (i + 4 < len) {
            //先找pps位置
            if (data[i] == 0x00 && data[i + 1] == 0x00
                && data[i + 2] == 0x00
                && data[i + 3] == 0x01) {
                if (data[i + 4] == 0x68) {
                    live->sps_len = i - 4;
                    //new一个数组
                    live->sps = static_cast<int8_t *>(malloc(live->sps_len));
                    //sps解析出来了
                    memcpy(live->sps, data + 4, live->sps_len);

                    //解析pps
                    live->pps_len = len - (4 + live->sps_len) - 4;
                    //实例化PPS 的数组
                    live->pps = static_cast<int8_t *>(malloc(live->pps_len));

                    memcpy(live->pps, data + 4 + live->sps_len + 4, live->pps_len);
                    LOGI("sps:%d pps:%d", live->sps_len, live->pps_len);
                    break;
                }
            }
        }
    }
}

// 三、封装sps和pps的RTMPPacket，rtmp传输sps和pps
RTMPPacket *createSpsPpsPackage(Live *live) {
    //sps  pps 的 packaet
    int body_size = 16 + live->sps_len + live->pps_len;
    RTMPPacket *packet = (RTMPPacket *) malloc(sizeof(RTMPPacket));
    //清空缓冲,实例化数据包
    RTMPPacket_Alloc(packet, body_size);
    int i = 0;
    packet->m_body[i++] = 0x17;
    //AVC sequence header 设置为0x00
    packet->m_body[i++] = 0x00;
    //CompositionTime
    packet->m_body[i++] = 0x00;
    packet->m_body[i++] = 0x00;
    packet->m_body[i++] = 0x00;
    //AVC sequence header
    packet->m_body[i++] = 0x01;
    //固定操作
    packet->m_body[i++] = live->sps[1]; //profile 编码质量 如baseline、main、 high
    packet->m_body[i++] = live->sps[2]; //profile_compatibility 兼容性
    packet->m_body[i++] = live->sps[3]; //profile level 编码等级
    packet->m_body[i++] = 0xFF;//已经规定好了
    packet->m_body[i++] = 0xE1; //reserved（111） + lengthSizeMinusOne（5位 sps 个数） 总是0xe1
    //高八位
    packet->m_body[i++] = (live->sps_len >> 8) & 0xFF;
    //低八位
    packet->m_body[i++] = live->sps_len & 0xff;
    //拷贝sps的内容
    memcpy(&packet->m_body[i], live->sps, live->sps_len);
    i += live->sps_len;
    //pps
    packet->m_body[i++] = 0x01; //pps number
    //pps length
    packet->m_body[i++] = (live->pps_len >> 8) & 0xff;
    packet->m_body[i++] = live->pps_len & 0xff;
    //拷贝pps内容
    memcpy(&packet->m_body[i], live->pps, live->pps_len);
    //设置packet的其它属性
    //视频类型
    packet->m_packetType = RTMP_PACKET_TYPE_VIDEO;
    packet->m_nBodySize = body_size;
    //视频 04
    packet->m_nChannel = 0x04;
    packet->m_nTimeStamp = 0;
    packet->m_hasAbsTimestamp = 0;
    packet->m_headerType = RTMP_PACKET_SIZE_LARGE;
    packet->m_nInfoField2 = live->rtmp->m_stream_id;
    return packet;
}

// 四、封装视频帧数据的RTMPPacket，rtmp传输帧数据
RTMPPacket *createVideoPackage(int8_t *buf, int len, const long tms, Live *live) {
    buf += 4;
    RTMPPacket *packet = (RTMPPacket *) malloc(sizeof(RTMPPacket));
    //长度
    int body_size = len + 9;
    //初始化RTMP内部的body数组
    RTMPPacket_Alloc(packet, body_size);

    if (buf[0] == 0x65) {
        //关键帧
        packet->m_body[0] = 0x17;
    } else {
        //非关键帧
        packet->m_body[0] = 0x27;
    }
    //固定的大小
    packet->m_body[1] = 0x01;
    packet->m_body[2] = 0x00;
    packet->m_body[3] = 0x00;
    packet->m_body[4] = 0x00;

    //长度
    packet->m_body[5] = (len >> 24) & 0xff;
    packet->m_body[6] = (len >> 16) & 0xff;
    packet->m_body[7] = (len >> 8) & 0xff;
    packet->m_body[8] = (len) & 0xff;

    //数据
    memcpy(&packet->m_body[9], buf, len);

    //设置packet的其它属性
    packet->m_packetType = RTMP_PACKET_TYPE_VIDEO;
    packet->m_nBodySize = body_size;
    packet->m_nChannel = 0x04;
    packet->m_nTimeStamp = tms;
    packet->m_hasAbsTimestamp = 0;
    packet->m_headerType = RTMP_PACKET_SIZE_LARGE;
    packet->m_nInfoField2 = live->rtmp->m_stream_id;
    return packet;
}

// 发送数据包
int sendPacket(RTMPPacket *packet) {
    int r = RTMP_SendPacket(live->rtmp, packet, 1);
    RTMPPacket_Free(packet);
    free(packet);
    return r;
}

// 五、发送视频数据
int sendVideo(int8_t *buf, int len, long tms) {
    int ret = 0;
    if (buf[4] == 0x67) {
        //缓存sps和pps到全局遍历,不需要推流
        if (live && (!live->pps || !live->sps)) {
            prepareVideo(buf, len, live);
        }
        return ret;
    }

    //I帧推之前需要推sps和pps
    if (buf[4] == 0x65) {
        //发送sps和pps
        RTMPPacket *packet = createSpsPpsPackage(live);
        sendPacket(packet);
    }
    //发送帧数据
    RTMPPacket *packet2 = createVideoPackage(buf, len, tms, live);
    ret = sendPacket(packet2);
    return ret;
}

// 六、封装音频帧数据RTMPPacket
RTMPPacket *createAudioPacket(int8_t *buf, const int len, const int type, const long tms,
                              Live *live) {

    //组装音频包,两个字节是固定的 如果是第一次发,就是 01,如果后面,00
    int body_size = len + 2;
    RTMPPacket *packet = (RTMPPacket *) malloc(sizeof(RTMPPacket));
    RTMPPacket_Alloc(packet, body_size);
    //音频头
    packet->m_body[0] = 0xAF;
    if (type == 1) {
        packet->m_body[1] = 0x00;
    }else{
        packet->m_body[1] = 0x01;
    }
    memcpy(&packet->m_body[2], buf, len);
    packet->m_packetType = RTMP_PACKET_TYPE_AUDIO;
    //音频通道id
    packet->m_nChannel = 0x05;
    packet->m_nBodySize = body_size;
    packet->m_nTimeStamp = tms;
    packet->m_hasAbsTimestamp = 0;
    packet->m_headerType = RTMP_PACKET_SIZE_LARGE;
    packet->m_nInfoField2 = live->rtmp->m_stream_id;
    return packet;
}

// 七、发送音频数据
int sendAudio(int8_t *buf, int len, int type, int tms) {
    RTMPPacket *packet = createAudioPacket(buf, len, type, tms, live);
    int ret=sendPacket(packet);
    return ret;
}

// 八、发送数据到服务器
extern "C"
JNIEXPORT jboolean JNICALL
Java_com_np_rtmpdump3_ScreenLive_sendData(JNIEnv *env, jobject thiz, jbyteArray data_, jint len,
                                          jlong tms, jint type) {
    // 确保不会取出空的 RTMP 数据包
    if (!data_) {
        return 0;
    }
    int ret;
    int8_t *data = env->GetByteArrayElements(data_, NULL);

    if (type == 1) {//视频
        LOGI("开始发送视频 %d", len);
        ret = sendVideo(data, len, tms);
    } else {//音频
        LOGI("开始发送音频 %d", len);
        //ret = sendAudio(data, len, tms, type);
    }

    env->ReleaseByteArrayElements(data_, data, 0);
    return ret;
}